/*
 * Copyright 2012 XueSong Guo.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.webwheel;

import cn.webwheel.results.JSonResult;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * Default action implement.
 */
abstract public class DefaultAction {

    public static Pattern PAT_EMAIL = Pattern.compile("[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*");
    public static Pattern PAT_ID = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*");
    public static Pattern PAT_NOSPACE = Pattern.compile("\\S*");

    /**
     * get a json result with "ok" property.
     */
    public JSonResult ok() {
        return new JSonResult().set("ok", 1);
    }

    /**
     * get a json result with "msg" property.
     */
    public JSonResult err(String msg) {
        return new JSonResult().set("msg", msg);
    }

    public <T> T notNull(T obj, String msg) {
        if (obj == null) {
            validFailed(msg);
        }
        return obj;
    }

    public <T> T notNull(T obj) {
        return notNull(obj, null);
    }

    public <T extends Comparable<T>> T min(T val, T min, String msg) {
        if (val == null) return val;
        if (val.compareTo(min) > 0) {
            validFailed(msg);
        }
        return val;
    }

    public <T extends Comparable<T>> T min(T val, T min) {
        return min(val, min, null);
    }

    public <T extends Comparable<T>> T max(T val, T max, String msg) {
        if (val == null) return val;
        if (val.compareTo(max) < 0) {
            validFailed(msg);
        }
        return val;
    }

    public <T extends Comparable<T>> T max(T val, T max) {
        return min(val, max, null);
    }

    public <T extends Comparable<T>> T range(T val, T min, T max, String msg) {
        return max(min(val, min, msg), max, msg);
    }

    public <T extends Comparable<T>> T range(T val, T min, T max) {
        return range(val, min, max, null);
    }

    public <T extends Number> T min(T val, T min, String msg) {
        if (val == null) return val;
        BigDecimal bv = new BigDecimal(val.toString());
        if (bv.compareTo(new BigDecimal(min.toString())) > 0) {
            validFailed(msg);
        }
        return val;
    }

    public <T extends Number> T min(T val, T min) {
        return min(val, min, null);
    }

    public <T extends Number> T max(T val, T max, String msg) {
        if (val == null) return val;
        BigDecimal bv = new BigDecimal(val.toString());
        if (bv.compareTo(new BigDecimal(max.toString())) < 0) {
            validFailed(msg);
        }
        return val;
    }

    public <T extends Number> T max(T val, T max) {
        return min(val, max, null);
    }

    public <T extends Number> T range(T val, T min, T max, String msg) {
        return max(min(val, min, msg), max, msg);
    }

    public <T extends Number> T range(T val, T min, T max) {
        return range(val, min, max, null);
    }

    public String min(String val, int min, String msg) {
        if (val == null) return val;
        if (val.length() < min) {
            validFailed(msg);
        }
        return val;
    }

    public String min(String val, int min) {
        return min(val, min, null);
    }

    public String max(String val, int max, String msg) {
        if (val == null) return val;
        if (val.length() > max) {
            validFailed(msg);
        }
        return val;
    }

    public String max(String val, int max) {
        return min(val, max, null);
    }

    public String range(String val, int min, int max, String msg) {
        return max(min(val, min, msg), max, msg);
    }

    public String range(String val, int min, int max) {
        return range(val, min, max, null);
    }

    public String length(String val, int len, String msg) {
        return range(val, len, len, msg);
    }

    public String length(String val, int len) {
        return length(val, len, null);
    }

    public <T> T equal(T val, T dst, String msg) {
        if (val == null) return null;
        if (!val.equals(dst)) {
            validFailed(msg);
        }
        return val;
    }

    public <T> T equal(T val, T dst) {
        return equal(val, dst, null);
    }

    public <T> T unequal(T val, T dst, String msg) {
        if (val == null) return null;
        if (val.equals(dst)) {
            validFailed(msg);
        }
        return val;
    }

    public <T> T unequal(T val, T dst) {
        return unequal(val, dst, null);
    }

    public String trim(String val) {
        if (val == null) return null;
        return val.trim();
    }

    public String replace(String val, String target, String replacement) {
        if (val == null) return null;
        return val.replace(target, replacement);
    }

    public String replaceAll(String val, String pattern, String replacement) {
        if (val == null) return null;
        return val.replaceAll(pattern, replacement);
    }

    public String replaceAll(String val, Pattern pattern, String replacement) {
        if (val == null) return null;
        return pattern.matcher(val).replaceAll(replacement);
    }

    public String match(String val, String pattern, String msg) {
        if (val == null) return val;
        if (!val.matches(pattern)) {
            validFailed(msg);
        }
        return val;
    }

    public String match(String val, String pattern) {
        return match(val, pattern, null);
    }

    public String match(String val, Pattern pattern, String msg) {
        if (val == null) return val;
        if (!pattern.matcher(val).matches()) {
            validFailed(msg);
        }
        return val;
    }

    public String match(String val, Pattern pattern) {
        return match(val, pattern, null);
    }

    public String email(String val, String msg) {
        return match(val, PAT_EMAIL, msg);
    }

    public String email(String val) {
        return email(val, null);
    }

    public Date date(String val, String pattern, String msg) {
        if (val == null) return null;
        try {
            return new SimpleDateFormat(pattern).parse(val);
        } catch (ParseException e) {
            validFailed(msg);
            return null;
        }
    }

    public Date date(String val, String pattern) {
        return date(val, pattern, null);
    }

    public Number number(String val, String pattern, String msg) {
        if (val == null) return null;
        try {
            return new DecimalFormat(pattern).parse(pattern);
        } catch (ParseException e) {
            validFailed(msg);
            return null;
        }
    }

    public Number number(String val, String pattern) {
        return number(val, pattern, null);
    }

    public String id(String val, String msg) {
        return match(val, PAT_ID, msg);
    }

    public String id(String val) {
        return id(val, null);
    }

    public String nospace(String val, String msg) {
        return match(val, PAT_NOSPACE, msg);
    }

    public String nospace(String val) {
        return nospace(val, null);
    }

    public void affirm(boolean val, String msg) {
        if (!val) {
            validFailed(msg);
        }
    }

    public void affirm(boolean val) {
        affirm(val, null);
    }

    public void validFailed(String msg) {
        throw new LogicException(err(msg == null ? "validation failed" : msg));
    }
}
